<template>
  <div class="lm-date" v-click-outside>
    <div class="lm-date-input">
      <span class="lm-date-input-pre">
        <lm-icon :name="icon" size="20"></lm-icon>
      </span>
      <input
        class="lm-date-input-inner"
        type="text"
        :value="formatDate"
        :placeholder="placeholder"
      />
    </div>
    <div class="lm-date-panel" v-if="visible">
      <div class="lm-pannel-nav">
        <span @click="preMonth">&lt;</span>
        <span @click="preYear">&lt;&lt;</span>
        <span @click="showYear">{{ time.year }}年</span>
        <span @click="showMonth">{{ time.month + 1 }}月</span>
        <span @click="nextYear">&gt;&gt;</span>
        <span @click="nextMonth">&gt;</span>
      </div>
      <transition name="fade">
        <div class="lm-pannel-content" v-if="!visibleMonth && !visibleYear">
          <div class="days">
            <span
              class="cell-top"
              v-for="(week, index) in weekDays"
              :key="index"
            >
              {{ week }}
            </span>
          </div>
          <div class="days" v-for="i in 6" :key="i">
            <!-- 直接列出6*7的列表 -->
            <span
              class="cell"
              :class="[
                {
                  notCurMonth: !isCurMonth(i, j),
                  isCurDay: isToday(i, j),
                  select: isSelect(i, j),
                },
              ]"
              v-for="j in 7"
              :key="j"
              @click.stop="chooseDate(i, j)"
            >
              {{ oneOfVisibleDays(i, j).getDate() }}
            </span>
          </div>
        </div>
      </transition>
      <transition name="fade">
        <div class="lm-pannel-content" v-if="visibleYear">
          <div class="days" v-for="i in 3" :key="i">
            <span
              class="cell-year"
              v-for="j in 4"
              :key="j"
              @click="showYearMonth(i, j, 'year')"
              >{{ oneOfVisibleYear(i, j) }}</span
            >
          </div>
        </div>
      </transition>
      <transition name="fade">
        <div class="lm-pannel-content" v-if="visibleMonth">
          <div class="days" v-for="i in 3" :key="i">
            <span
              class="cell-year"
              v-for="j in 4"
              :key="j"
              @click="showYearMonth(i, j, 'month')"
              >{{ oneOfVisibleMonth(i, j) }}月</span
            >
          </div>
        </div>
      </transition>
      <div class="lm-pannel-footer" @click="setToday">今天</div>
    </div>
  </div>
</template>

<script>
import { getYearMonthDay, getDate } from "../../utils/index";
export default {
  name: "LmDatePicker",
  directives: {
    clickOutside: {
      // 指令的生命周期
      bind(el, bindings, vnode) {
        /** el可以获取当前dom节点，并且进行编译，也可以操作事件 **/
        /** binding指的是一个对象，一般不用 **/
        /** vnode 是 Vue 编译生成的虚拟节点 **/
        // 把事件绑定给document上，看一下点击的是否是当前这个元素内部
        let handler = (e) => {
          // e是事件源
          // console.log(e.target, "eee");
          if (el.contains(e.target)) {
            // 判断是否包含target
            // console.log("包含");
            // 判断一下当前面板是否已经显示出来了
            if (!vnode.context.visible) {
              vnode.context.focusFn();
              console.log("focusFn");
            }
          } else {
            // console.log("不包含");
            if (vnode.context.visible) {
              vnode.context.blurFn();
              console.log("blurFn");
            }
          }
        };
        el.handler = handler;
        document.addEventListener("click", handler);
      },
      unbind(el) {
        // 移除
        document.removeEventListener("click", el.handler);
      },
    },
  },
  data() {
    let { year, month } = getYearMonthDay(this.value);
    return {
      weekDays: ["日", "一", "二", "三", "四", "五", "六"],
      visible: false, // 控制面板的隐藏于显示
      time: { year, month },
      visibleYear: false,
      visibleMonth: false,
    };
  },
  props: {
    value: {
      type: Date,
      default: () => new Date(), // 返回的默认值必须是一个函数类型
    },
    placeholder: {
      type: String,
      default: "选择日期",
    },
    icon: {
      type: String,
      default: "005-calendar",
    },
  },
  computed: {
    // 计算要渲染的天数（日期）
    visibleDays() {
      this.visibleYear = false;
      this.visibleMonth = false;
      let { year, month } = getYearMonthDay(
        getDate(this.time.year, this.time.month, 1)
      );
      // 获取当前月第一天
      let currentFirstDay = getDate(year, month, 1);
      // 获取当前月第一天星期几
      let week = currentFirstDay.getDay();
      // 当前开始的天数
      let startDay = currentFirstDay - week * 60 * 60 * 1000 * 24;
      // 循环42天
      let arr = [];
      for (let i = 0; i < 42; i++) {
        arr.push(new Date(startDay + i * 60 * 60 * 1000 * 24));
      }
      return arr;
    },
    // 计算要渲染的年
    effectiveYear() {
      this.visibleMonth = false;
      this.visibleYear = true;
      let { year, month } = getYearMonthDay(
        getDate(this.time.year, this.time.month, 1)
      );
      let arr = [];
      for (let i = 0; i < 12; i++) {
        let { year: y } = getYearMonthDay(getDate(year, month, 1));
        arr.push(y);
        year--;
      }
      return arr;
    },
    // 计算要渲染的月
    effectiveMonth() {
      this.visibleMonth = false;
      this.visibleYear = true;
      let arr = [];
      for (let i = 0; i < 12; i++) {
        arr.push(i + 1);
      }
      return arr;
    },
    // 计算日期
    formatDate() {
      let { year, month, day } = getYearMonthDay(this.value);
      return `${year}-${month + 1}-${day}`;
    },
  },
  mounted() {
    // console.log(this.effectiveMonth, "effectiveMonth");
  },
  methods: {
    // 组件内部方法：
    focusFn() {
      // 显示面板
      this.visible = true;
    },
    blurFn() {
      // 隐藏面板
      this.visible = false;
    },
    // 循环遍历取的某一天
    oneOfVisibleDays(i, j) {
      return this.visibleDays[(i - 1) * 7 + (j - 1)];
    },
    oneOfVisibleYear(i, j) {
      return this.effectiveYear[(i - 1) * 3 + (j - 1)];
    },
    oneOfVisibleMonth(i, j) {
      return this.effectiveMonth[(i - 1) * 3 + (j - 1)];
    },
    // 计算日期是否属于当前月份
    isCurMonth(i, j) {
      let date = this.oneOfVisibleDays(i, j);
      // 判断是不是当月
      let { year, month } = getYearMonthDay(
        getDate(this.time.year, this.time.month, 1)
      );
      let { year: y, month: m } = getYearMonthDay(date);
      return year === y && month === m;
    },
    // 判断是否是今天
    isToday(i, j) {
      let date = this.oneOfVisibleDays(i, j);
      // 判断是不是今天
      // let { year, month, day } = getYearMonthDay(this.value);
      let { year, month, day } = getYearMonthDay(new Date());
      let { year: y, month: m, day: d } = getYearMonthDay(date);
      return year === y && month === m && day === d;
    },
    // 选择日期
    chooseDate(i, j) {
      let date = this.oneOfVisibleDays(i, j);
      this.time = getYearMonthDay(date);
      this.$emit("input", date);
      this.blurFn();
    },
    // 判断是否选中
    isSelect(i, j) {
      let date = this.oneOfVisibleDays(i, j);
      let { year, month, day } = getYearMonthDay(this.value);
      let { year: y, month: m, day: d } = getYearMonthDay(date);
      // console.log(year === y && month === m && day === d);
      return year === y && month === m && day === d;
    },
    // 上个月
    preMonth() {
      // 获取当前的年月的一个日期
      let d = getDate(this.time.year, this.time.month, 1);
      d.setMonth(d.getMonth() - 1);
      this.time = getYearMonthDay(d);
    },
    // 上一年
    preYear() {
      let d = getDate(this.time.year, this.time.month, 1);
      d.setFullYear(d.getFullYear() - 1);
      this.time = getYearMonthDay(d);
    },
    // 下个月
    nextMonth() {
      // 获取当前的年月的一个日期
      let d = getDate(this.time.year, this.time.month, 1);
      d.setMonth(d.getMonth() + 1);
      this.time = getYearMonthDay(d);
    },
    // 下一年
    nextYear() {
      // 获取当前的年月的一个日期
      let d = getDate(this.time.year, this.time.month, 1);
      d.setFullYear(d.getFullYear() + 1);
      this.time = getYearMonthDay(d);
    },
    // 点击年展示10个年
    showYear() {
      this.visibleYear = true;
      this.visibleMonth = false;
    },
    // 点击展示12个月
    showMonth() {
      this.visibleMonth = true;
      this.visibleYear = false;
    },
    // 展示具体某个月的每一天
    showYearMonth(i, j, str) {
      this.visibleMonth = false;
      this.visibleYear = false;
      if (str === "year") {
        //年
        let y = this.oneOfVisibleYear(i, j);
        let d = getDate(y, this.time.month, 1);
        this.time = getYearMonthDay(d);
        // console.log(y, "yyy");
        // console.log(d, "dddd");
        this.$emit("input", d);
      } else if (str === "month") {
        // 月
        // 点击的月份
        let m = this.oneOfVisibleMonth(i, j) - 1;
        // console.log(m, "mmm");
        // 获取时间
        let d = getDate(this.time.year, m, 1);
        this.time = getYearMonthDay(d);
        // console.log(d, "dddd");
        this.$emit("input", d);
      }
    },
    // 点击今天
    setToday() {
      let d = new Date();
      this.time = getYearMonthDay(d);
      this.$emit("input", d);
    },
  },
};
</script>

<style lang="scss" scoped>
.lm-date {
  width: 100%;
  z-index: 999;
  position: relative;
}
.lm-date-input {
  width: 140px;
  height: 40px;
  box-sizing: border-box;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: relative;
  .lm-date-input-inner {
    width: 100%;
    height: 100%;
    position: absolute;
    left: 0;
    right: 0;
    border: 1px solid #dcdfe6;
    outline: none;
    font-size: 15px;
    text-align: center;
    box-sizing: border-box;
    border-radius: 4px;
  }
}
.lm-date-input-pre {
  position: absolute;
  left: 10px;
  z-index: 2;
}
.lm-date-input-inner:focus {
  border: 1px solid #409eff;
}
.lm-date-panel {
  width: 32 * 7px;
  position: absolute;
  background: #fff;
  box-shadow: 2px 2px 2px 5px #f5f1f1e0;
  .lm-pannel-nav {
    display: flex;
    justify-content: space-around;
    height: 30px;
    span {
      cursor: pointer;
      user-select: none;
    }
  }
  .lm-pannel-content {
    // width: 32px;
    .days {
      width: 100%;
      display: inline-flex;
      justify-content: space-around;
      .cell {
        width: 32px;
        height: 32px;
        display: inline-flex;
        justify-content: center;
        align-items: center;
        cursor: pointer;
        font-weight: bold;
        box-sizing: border-box;
      }
      .cell:hover,
      .select {
        border-radius: 50%;
        border: 1px solid hotpink;
      }
      .cell-top {
        width: 32px;
        height: 32px;
        display: inline-flex;
        justify-content: center;
        align-items: center;
        cursor: pointer;
        font-weight: bold;
        box-sizing: border-box;
      }
      .cell-year {
        font-weight: bold;
        margin-bottom: 10px;
        cursor: pointer;
      }
    }
  }
  .lm-pannel-footer {
    height: 30px;
    text-align: center;
    cursor: pointer;
  }
}
.notCurMonth {
  color: grey;
}
.notCurMonth:hover {
  // cursor: no-drop !important;
  // border: none !important;
}
.isCurDay {
  border-radius: 50%;
  background: hotpink;
}
.isBorder {
  border: 1px solid hotpink;
}

// 进入动画
.fade-enter-active {
  animation: fade-enter 0.5s;
}
// 离开的动画
.fade-leave-active {
  // animation: fade-leave 0.5s;
}
@keyframes fade-enter {
  0% {
    opacity: 0;
    transform: rotateY(0deg);
  }
  100% {
    opacity: 1;
    transform: rotateY(90deg);
  }
}

@keyframes fade-leave {
  0% {
    opacity: 0;
    transform: rotateX(0deg);
  }
  100% {
    opacity: 1;
    transform: rotateX(90deg);
  }
}
</style>